import socket
import select
import stackless
import thread
import hmac

def recv_data(sock):
    print "receiving"
    sock.setblocking(0)
    poller = select.poll()
    poller.register(sock, select.POLLIN)
    while True:
        if poller.poll(0):
            print "recv"
            return sock.recv(1024)
        stackless.schedule()

def send_data(sock, data):
    print "send"
    sock.setblocking(0)
    poller = select.poll()
    poller.register(sock, select.POLLOUT)
    while True:
        if poller.poll(0):
            sent = sock.send(data)
            print "sent", sent, data
            if sent == len(data):
                break
            else:
                data = data[sent:]
        stackless.schedule()

def sl_logon_client(address, port, world, username, key):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((address, port))
    send_data(sock, username)
    clear_text = recv_data(sock)
    print clear_text
    cipher_text = hmac.new(key, clear_text).hexdigest()
    print cipher_text
    send_data(sock, cipher_text)
    if recv_data(sock) == "Authenticated":
        print "connected"
        #stackless.tasklet(world.Player)(Vector(0,0,0), world, username)
        world.send(("UJOIN", ""))
    else:
        print "couldn't connect"
    sock.close()

def sl_send_client(address, port, world):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.setblocking(0)
    sock.bind((address, port))
    poller = select.poll()
    poller.register(sock, select.POLLOUT)
    while True:
        data = world.receive()
        while not poller.poll(0):
            # Waits till we can send something
            stackless.schedule()
        sock.send(data)

def sl_receive_client(address, port, world):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.setblocking(0)
    sock.bind((address, port))
    poller = select.poll()
    poller.register(sock, select.POLLIN)
    while True:
        if poller.poll(0):
            data, recvd_address = sock.recvfrom(1024)
            if recvd_address == address:
                world.send(("DATA", data))
            stackless.schedule()

def logon_client(address, port, world, username, key):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((address, port))
    sock.send(username)
    clear_text = sock.recv(1024)
    print clear_text
    cipher_text = hmac.new(key, clear_text).hexdigest()
    print cipher_text
    sock.send(cipher_text)
    r = sock.recv(1024)
    print r
    if r == "Authenticated":
        print "w00t we're in!"
    else:
        print "buggery!"
    sock.close()

def send_client(address, port, world):
    print "sc"
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind((address, port))
    while True:
        data = world.receive()
        #print "sc", world, data
        print "sending to server"#, data
        sock.send(data)
        print "sent to server"

def receive_client(address, port, world):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind((address, port))
    while True:
        data, recvd_address = sock.recvfrom(1024)
        if recvd_address == address:
            world.send(("DATA", data))
        stackless.schedule()

def start(address, port, world, world_send, username, key):
    thread.start_new_thread(logon_client,
                            (address, port, world, username, key))
    thread.start_new_thread(send_client, (address, 45988, world_send))
    thread.start_new_thread(receive_client, (address, 23854, world))
    

if __name__ == "__main__":
    start()
    #c = stackless.channel()
    #stackless.tasklet(logon_client)("localhost", 45984, c, "Bobo", "Hadoken")
    #stackless.tasklet(send_client)("localhost", 37654, c)
    #stackless.tasklet(receive_client)("localhost", 37655, c)
    #stackless.run()
